﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;

namespace DynamicGeometry
{
    public partial class StyleManager : CollectionWithEvents<IFigureStyle>
    {
        public StyleManager(Drawing drawing)
        {
            AddDefaultStyles();
            Drawing = drawing;
        }

        protected override void OnItemAdded(IFigureStyle item)
        {
            if (item.Name.IsEmpty())
            {
                item.Name = GenerateUniqueName();
            }
        }

        string GenerateUniqueName()
        {
            int n = 1;
            while (this[n.ToString()] != null)
            {
                n++;
            }
            return n.ToString();
        }

        public IFigureStyle this[string index]
        {
            get
            {
                foreach (var style in this)
                {
                    if (style.Name == index)
                    {
                        return style;
                    }
                }
                return null;
            }
        }

        public IEnumerable<TStyle> GetStyles<TStyle>() 
            where TStyle : class, IFigureStyle
        {
            foreach (var style in this)
            {
                TStyle correctStyle = style as TStyle;
                if (correctStyle != null)
                {
                    yield return correctStyle;
                }
            }
        }

        public Drawing Drawing { get; set; }

        public void AddDefaultStyles()
        {
            var freePointStyle = new PointStyle();
            var pointOnFigureStyle = new PointStyle();
            var dependentPointStyle = new PointStyle();
            var lineStyle = new LineStyle();
            var shapeStyle = new ShapeStyle()
                {
                    Color = Colors.Transparent
                };
            var textStyle = new TextStyle()
                {
                    FontSize = 14
                };
            var hyperLinkStyle = new TextStyle();

            this.AddRange(new IFigureStyle[] 
            { 
                freePointStyle, 
                pointOnFigureStyle, 
                dependentPointStyle,
                lineStyle,
                shapeStyle,
                textStyle,
                hyperLinkStyle
            });
        }

        public IEnumerable<IFigureStyle> GetSupportedStyles(IFigure figure)
        {
            return GetSupportedStyles(figure.GetType());
        }

        public IEnumerable<IFigureStyle> GetSupportedStyles(Type figureType)
        {
            foreach (var style in this)
            {
                if (style.GetType().SupportsFigureType(figureType))
                {
                    yield return style;
                }
            }
        }

        public IFigureStyle AssignDefaultStyle(IFigure figure)
        {
            var supportedStyles = GetSupportedStyles(figure);
            return PickMoreDerivedStyle(supportedStyles);
        }

        IFigureStyle PickMoreDerivedStyle(IEnumerable<IFigureStyle> supportedStyles)
        {
            IFigureStyle mostDerivedSoFar = null;
            Type mostDerivedType = null;
            foreach (var item in supportedStyles)
            {
                if (mostDerivedSoFar == null)
                {
                    mostDerivedSoFar = item;
                    mostDerivedType = mostDerivedSoFar.GetType();
                }
                else
                {
                    if (mostDerivedType.IsAssignableFrom(item.GetType()))
                    {
                        mostDerivedSoFar = item;
                        mostDerivedType = item.GetType();
                    }
                }
            }
            return mostDerivedSoFar;
        }

        public IFigureStyle CreateNewStyle(IFigure figure)
        {
            var newStyle = figure.Style.Clone();
            this.Add(newStyle, Drawing.ActionManager);
            return newStyle;
        }

        static IEnumerable<Type> StyleTypes = Reflector.DiscoverTypes<IFigureStyle>();

        public static IFigureStyle CreateStyleByTypeName(string name)
        {
            var type = StyleTypes.First(t => t.Name == name);
            return (IFigureStyle)Activator.CreateInstance(type);
        }

        public IFigureStyle FindExistingOrAddNew(IFigureStyle style)
        {
            var found = this
                .Where(s => s.ToString() == style.ToString())
                .FirstOrDefault();
            if (found != null)
            {
                return found;
            }

            this.Add(style, Drawing.ActionManager);
            return style;
        }
    }
}